package com.sky.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.sky.dto.GoodsSalesDTO;
import com.sky.dto.OrderDTO;
import com.sky.dto.OrdersDTO;
import com.sky.entity.OrderDetail;
import com.sky.entity.Orders;
import com.sky.entity.User;
import com.sky.mapper.EmployeeMapper;
import com.sky.mapper.OrdersMapper;
import com.sky.mapper.UserMapper;
import com.sky.service.ReportService;
import com.sky.service.WorkspaceService;
import com.sky.vo.*;
import io.swagger.models.auth.In;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Slf4j
@Service
public class ReportServiceImpl implements ReportService {



    @Autowired
    private OrdersMapper ordersMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private WorkspaceService workspaceService;

    /**
     * 营业额统计
     * ├─ dateList	string	必须		日期列表，日期之间以逗号分隔
     * ├─ turnoverList	string	必须		营业额列表，营业额之间以逗号分隔
     *
     * @param begin
     * @param end
     * @return
     */
    @Override
    public TurnoverReportVO turnoverStatistics(LocalDate begin, LocalDate end) {
        // 1.获取，解析 dataList 日期字符串列表
        String stringRange = dataToStringRange(begin.toString(),end.toString());
        String[] stringList = stringRange.split(",");
        // 2.根据日期查询  对应的订单营业额
        List<Orders> orders =ordersMapper.turnoverStatistics(begin.toString(),end.toString());
        log.info("查询出来的日期列表有：{}",orders.size());
        // 3.根据日期，批量获取对应的日期的营业额
            // 营业额列表，依次对应 日期列表
        List<String> turnoverList=new ArrayList<>();
        if(ObjectUtil.isNotNull(orders)&&orders.size()>0){
            for(String time:stringList){
                log.info("现在统计日期为：{}的营业额",time);
                final BigDecimal[] anotherAmount = {new BigDecimal("0")};
                // 指定日期的全部
                orders.stream().forEach(order -> {
                    String format =  order.getOrderTime().format(DateTimeFormatter.ISO_LOCAL_DATE);
                    if(format.equals(time)){ // 如果是 相同日期的订单 则统计
                        anotherAmount[0] = anotherAmount[0].add(order.getAmount());
                    }
                });
                log.info("{}的总营业额为：{}",time, anotherAmount[0]);
                turnoverList.add(anotherAmount[0].toString()); // 记录指定日期的总营业额
            }
        }
        // 4.返回指定格式的数据对象
        TurnoverReportVO reportVO = new TurnoverReportVO();
        reportVO.setDateList(stringRange);
        reportVO.setTurnoverList(turnoverList.stream().map(Object::toString).collect(Collectors.joining(",")));
        log.info("返回统计结果：{}",reportVO);
        return reportVO;
    }



    /**
     * 用户统计
     * ├─ dateList	string	必须		日期列表，以逗号分隔
     * ├─ newUserList	string	必须		新增用户数列表，以逗号分隔
     * ├─ totalUserList	string	必须		总用户量列表，以逗号分隔
     *
     * @param begin
     * @param end
     * @return
     */
    @Override
    public UserReportVO userStatistics(LocalDate begin, LocalDate end) {
        // 1. 日期列表
        String stringRange = dataToStringRange(begin.toString(), end.toString());
        String[] stringList= stringRange.split(",");
        // 2. 查询  新增用户数列表
        // 统计指定日期的注册人数列表，与日期列表 一一对应
        ArrayList<Integer> totalUserList = new ArrayList<>();
        // 分别统计每天 注册的总人数
        for (String time:stringList){
            // select count(id) from user where create_time < '2025-06-23'
            LocalDate nextTime=LocalDate.parse(time).plusDays(1);// 统计当前的 日期要加一,意思为包括当前的时间23：59：59
            Integer total=userMapper.getTotalUserByCreateTime(nextTime.toString());
            totalUserList.add(total);
            log.info("{}日的总用户为:{}人",time,total);
        }

        // 统计每天新增的用户数量
        ArrayList<Object> newUserList = new ArrayList<>();
        for (String time:stringList){
            LocalDate nextTime=LocalDate.parse(time).plusDays(1);
            Integer total=userMapper.getNewUserByCreateTime(time,nextTime.toString());
            newUserList.add(total);
            log.info("{}的新增用户为:{}人",time,total);
        }
        // 3.返回指定的对象格式
        UserReportVO userReportVO = new UserReportVO();

        userReportVO.setDateList(stringRange);
        // 每日总用户数列表字符串，以逗号分隔
        userReportVO.setTotalUserList(totalUserList.stream().map(Object::toString).collect(Collectors.joining(",")));
        // 每日新增用户数列表字符串，以逗号分隔
        userReportVO.setNewUserList(newUserList.stream().map(Object::toString).collect(Collectors.joining(",")));

        return userReportVO;
    }


    /**
     * 订单统计
     *
     * ├─ dateList	string	必须		日期列表，以逗号分隔
     * ├─ orderCompletionRate	number	必须		订单完成率
     * format: double
     *
     * ├─ orderCountList	string	必须		订单数列表，以逗号分隔
     * ├─ totalOrderCount	integer	必须		订单总数
     * format: int32
     *
     * ├─ validOrderCount	integer	必须		有效订单数
     * format: int32
     *
     * ├─ validOrderCountList	string	必须		有效订单数列表，以逗号分隔
     * @param begin
     * @param end
     * @return
     */
    @Override
    public OrderReportVO ordersStatistics(LocalDate begin, LocalDate end) {

        String stringRange = dataToStringRange(begin.toString(), end.toString());
        String[] stringList = stringRange.split(",");

        // 1.构建需要参数
            // 订单数列表
        List<Orders> ordersListAll=ordersMapper.getByOrderTime(begin.toString(),end.toString());

        ArrayList<Integer> orderCountList = new ArrayList<>();
        if(ObjectUtil.isNotNull(ordersListAll)&&ordersListAll.size()>0){
            for(String time:stringList){
                Integer total=0;
                for(Orders order:ordersListAll){
                    if(time.equals(order.getOrderTime().format(DateTimeFormatter.ISO_LOCAL_DATE))){
                        total++;
                    }
                }
                orderCountList.add(total);
            }
        }
            // 订单总数
        Integer totalOrderCount=ordersListAll.size();
        log.info(" {} - {} 订单总数为：{}",begin,end,totalOrderCount);
            // 有效订单数列表
        List<Orders> ordersListValid = ordersListAll.stream().filter(orders -> {
            return orders.getStatus() == Orders.COMPLETED;
        }).collect(Collectors.toList());

        ArrayList<Integer> validOrderCountList = new ArrayList<>();
        if(ObjectUtil.isNotNull(ordersListValid)&&ordersListValid.size()>0){
            for(String time:stringList){
                Integer total=0;
                for(Orders order:ordersListValid){
                    if(time.equals(order.getOrderTime().format(DateTimeFormatter.ISO_LOCAL_DATE))){
                        total++;
                    }
                }
                validOrderCountList.add(total);
            }
        }
            // 有效订单数
        int validOrderCount = ordersListValid.size();
        log.info(" {} - {} 有效订单总数为：{}",begin,end,validOrderCount);
            //  订单完成率
        double orderCompletionRate= (double) validOrderCount /totalOrderCount;

        // 2.返回 需要的数据对象
        OrderReportVO reportVO = new OrderReportVO();
        // 指定日期列表
        reportVO.setDateList(stringRange);
        // 订单数列表
        reportVO.setOrderCountList(orderCountList.stream().map(Object::toString).collect(Collectors.joining(",")));
        reportVO.setTotalOrderCount(totalOrderCount); // 订单总数
        // 有效订单数列表
        reportVO.setValidOrderCountList(validOrderCountList.stream().map(Object::toString).collect(Collectors.joining(",")));
        reportVO.setValidOrderCount(validOrderCount);   // 有效订单数
        reportVO.setOrderCompletionRate(orderCompletionRate);    //  订单完成率
        return reportVO;
    }


    /**
     * 商品销量top10
     *
     * ├─ nameList	string	必须		商品名称列表，以逗号分隔
     * ├─ numberList	string	必须		销量列表，以逗号分隔
     *
     * @param begin
     * @param end
     * @return
     */
    @Override
    @Transactional(readOnly = true)
    public SalesTop10ReportVO topTen(LocalDate begin, LocalDate end) {
        // 1. 查询指定时间的全部订单
        List<OrderDTO> dtoByOrderTime = ordersMapper.getOrdersDTOByOrderTime(begin.toString(), end.toString());
        log.info("查询到全部订单：{}", dtoByOrderTime);

        // 2. 获取全部的订单详情
        List<OrderDetail> orderDetails = dtoByOrderTime.stream()
                .map(OrderDTO::getOrderDetails)
                .filter(Objects::nonNull)
                .flatMap(List::stream)
                .collect(Collectors.toList());

        // 3. 统计每个商品的销量
        Map<String, Integer> salesMap = orderDetails.stream()
                .collect(Collectors.toMap(
                        OrderDetail::getName, // 键：商品名称
                        OrderDetail::getNumber, // 值：销量
                        Integer::sum // 如果有重复的商品名称，销量相加
                ));

        // 4. 按销量降序排序并取前10名
        List<Map.Entry<String, Integer>> topTenSales = salesMap.entrySet().stream()
                .sorted(Map.Entry.<String, Integer>comparingByValue().reversed())
                .limit(10)
                .collect(Collectors.toList());

        // 5. 构建返回结果
        SalesTop10ReportVO salesTop10ReportVO = new SalesTop10ReportVO();
        List<String> nameList = topTenSales.stream().map(Map.Entry::getKey).collect(Collectors.toList());
        List<String> numberList = topTenSales.stream().map(entry -> entry.getValue().toString()).collect(Collectors.toList());
        //String collect = topTenSales.stream().map(Map.Entry::getValue).map(Object::toString).collect(Collectors.joining(","));

        salesTop10ReportVO.setNameList(String.join(",", nameList));
        salesTop10ReportVO.setNumberList(String.join(",", numberList));

        return salesTop10ReportVO;
    }


    /**
     * 商品销量top10
     *
     * @param begin
     * @param end
     * @return
     */
    @Override
    public SalesTop10ReportVO getTopTen(LocalDate begin, LocalDate end) {
        // 查询 top 10
        List<GoodsSalesDTO> goodsSalesDTOS=ordersMapper.getTopTen(begin.toString(),end.toString());
        // 构建字符串
        String nameList = goodsSalesDTOS.stream().map(GoodsSalesDTO::getName).collect(Collectors.joining(","));
        String numberList = goodsSalesDTOS.stream().map(GoodsSalesDTO::getNumber).map(Object::toString).collect(Collectors.joining(","));
        log.info("查询到top10菜品为：");
        goodsSalesDTOS.forEach(System.out::println);
        return SalesTop10ReportVO.builder()
                .nameList(nameList)
                .numberList(numberList)
                .build();
    }

    /**
     *  将 起始日期 和 结束 的全部日期拼接成 字符串
     * @param begin
     * @param end
     * @return
     */
    public String  dataToStringRange(String begin,String end){

        // 将字符串转换为LocalDate对象
        LocalDate startDate = LocalDate.parse(begin);
        LocalDate endDate = LocalDate.parse(end);

        // 创建一个列表来存储日期字符串
        List<String> dateList = new ArrayList<>();

        // 循环从开始日期到结束日期
        while (!startDate.isAfter(endDate)) {
            // 将日期格式化为字符串并添加到列表中
            dateList.add(startDate.format(DateTimeFormatter.ISO_LOCAL_DATE));
            // 日期加一天
            startDate = startDate.plusDays(1);
        }

        // 将日期列表拼接成字符串
        String dateRange = String.join(",", dateList);
        System.out.println(dateRange);
        return dateRange;
    }


    /**
     * 导出excel报表
     *
     * @param httpServletResponse
     */
    @Override
    public void exportBusinessDate(HttpServletResponse httpServletResponse){
        // 近 （30天前的数据）
        LocalDate startDate = LocalDate.now().plusDays(-30); // 30天前
        LocalDate endDate = LocalDate.now().plusDays(-1);
        // 1.查询相关的数据
        BusinessDataVO businessDataVO = workspaceService.getBusinessData(startDate.toString(),endDate.toString());
        // 2.读取excel模版写入数据
        InputStream fileInputStream = this.getClass().getClassLoader().getResourceAsStream("template/运营数据报表模板.xlsx");
        // 获取excel 文件对象
        try{
            XSSFWorkbook excel= null;
            if (fileInputStream != null) {
                excel = new XSSFWorkbook(fileInputStream);
            }
            XSSFSheet sheet = excel.getSheetAt(0); // 获取 sheet 页根据索引
            // 写入时间信息
            XSSFRow row = sheet.getRow(1);
            row.getCell(1).setCellValue("时间："+startDate.toString()+" ~~~ "+endDate.toString());
            // 写入概览数据
            row=sheet.getRow(3);
            row.getCell(2).setCellValue(businessDataVO.getTurnover());
            row.getCell(4).setCellValue(businessDataVO.getOrderCompletionRate());
            row.getCell(6).setCellValue(businessDataVO.getNewUsers());
            row=sheet.getRow(4);
            row.getCell(2).setCellValue(businessDataVO.getValidOrderCount());
            row.getCell(4).setCellValue(businessDataVO.getUnitPrice());
            // 明细数据
            int rownum=7;
            // 循环查询30天的明细统计数据
            for(int i=0;i<30;i++){
                // 开始天数
                LocalDate beginDay=startDate.plusDays(i); // 天数累加
                // 结束天数
                LocalDate overDay=beginDay.plusDays(1);
                BusinessDataVO businessData = workspaceService.getBusinessData(beginDay.toString(), overDay.toString());
                // 获取行数
                row=sheet.getRow(rownum+i);
                // 设置单元格数据
                row.getCell(1).setCellValue(beginDay.toString());
                row.getCell(2).setCellValue(businessData.getTurnover());
                row.getCell(3).setCellValue(businessData.getValidOrderCount());
                row.getCell(4).setCellValue(businessData.getOrderCompletionRate());
                row.getCell(5).setCellValue(businessData.getUnitPrice());
                row.getCell(6).setCellValue(businessData.getNewUsers());
            }

            // 3.通过输出流，将excel文件下载到浏览器 到客户
                // 这个输出流用于将数据写入HTTP响应体中，最终发送给客户端浏览器。
            ServletOutputStream outputStream = httpServletResponse.getOutputStream();
                // 将Excel文件的二进制数据写入到HTTP响应体中。
            excel.write(outputStream); // 将数据写入excel对象
            // 刷新输出流
            outputStream.flush();

            // 4.关闭资源
            fileInputStream.close();
            excel.close();

        }catch (IOException ioException){
            ioException.printStackTrace();
        }
    }




}
